#include "Buffer.h"


Buffer::Buffer(unsigned int size) :
_sizeMax(size),
_size(0),
_minSizeEvent(size * 2),
_checkEvent(true)
{
	_data = new char[_minSizeEvent];
	_currentStart = 0;
	_end = 0;
}

Buffer::~Buffer()
{
	
	std::list<EventOnEnoughData*>::iterator it = this->_listEventOnEnoughData.begin();
	std::list<EventOnEnoughData*>::iterator end = this->_listEventOnEnoughData.end();
	for(; it != end; ++it)
	{
		delete *it;
	}
	delete[] _data;
}

void Buffer::SetEvent(bool status)
{
	_checkEvent = status;
}

int Buffer::Write(void *tmp_data, unsigned int size)
{
	if (this->_size + size > _sizeMax)
	{
		return (-1);
	}
	int remain = this->_end + size - this->_sizeMax;
	if (remain > 0)
	{
		memcpy(this->_data + this->_end, tmp_data, size - remain);
		memcpy(this->_data, static_cast<char*>(tmp_data) + size - remain, remain);
		this->_end = remain;
	}
	else
	{
		memcpy(this->_data + this->_end, tmp_data, size);
		this->_end += size;
	}
	this->_size += size;
	if (this->_checkEvent && this->_size >= this->_minSizeEvent)
	{
		std::list<EventOnEnoughData*>::iterator it = this->_listEventOnEnoughData.begin();
		std::list<EventOnEnoughData*>::iterator end = this->_listEventOnEnoughData.end();

		for(; it != end; ++it)
		{
			if ((*it)->size <= this->_size)
			{
				(*((*it)->function))(this, (*it)->_udata);
			}
		}
	}
	return (0);
}


unsigned int Buffer::Size()
{
	return this->_size;
}

unsigned int Buffer::SizeMax()
{
	return this->_sizeMax;
}

void Buffer::Clean()
{
	_currentStart = 0;
	_end = 0;
	_size = 0;
}


void*  Buffer::Read(unsigned int size, bool delDataReaded)
{
	if (size > this->_size)
		size = this->_size;
	void *res = this->_data + this->_currentStart;

	int remain = size + this->_currentStart - this->_sizeMax;
	if (remain > 0)
	{
		memcpy(this->_data + size + this->_currentStart - remain, this->_data, remain);
		if (delDataReaded)
		{
			this->_currentStart = (this->_currentStart + size) - this->_sizeMax;
			this->_size -= size;
		}
	}
	else if (delDataReaded)
	{
		this->_currentStart = this->_currentStart + size;
		this->_size -= size;
	}

	return res;
}

void   Buffer::Delete(unsigned int size)
{
	if (size > this->_size)
		size = this->_size;
	int remain = size + this->_currentStart - this->_sizeMax;

	if (remain > 0)
	{
		this->_currentStart = (this->_currentStart + size) - this->_sizeMax;
		this->_size -= size;
	}
	else
	{
		this->_currentStart = this->_currentStart + size;
		this->_size -= size;
	}
}

void Buffer::SubscribeEnoughData(ActOnBuffer function, unsigned int size, void *udata)
{
	EventOnEnoughData *toAdd = new EventOnEnoughData();

	toAdd->function = function;
	toAdd->size = size;
	toAdd->_udata = udata;

	this->_listEventOnEnoughData.push_front(toAdd);
	if (size < this->_minSizeEvent)
		this->_minSizeEvent = size;
	
}

void Buffer::UnsubscribeEnoughData(ActOnBuffer function, unsigned int size)
{
	std::list<EventOnEnoughData*> toRemove;

	std::list<EventOnEnoughData*>::iterator it = this->_listEventOnEnoughData.begin();
	std::list<EventOnEnoughData*>::iterator end = this->_listEventOnEnoughData.end();
	this->_minSizeEvent = _sizeMax * 2;
	for(; it != end; ++it)
	{
		if ((*it)->function == function && (*it)->size == size)
			toRemove.push_front(*it);
		else
		{
			if (this->_minSizeEvent > (*it)->size)
				this->_minSizeEvent = (*it)->size;
		}
	}

	it = toRemove.begin();
	end = toRemove.end();

	for(; it != end; ++it)
	{
		this->_listEventOnEnoughData.remove(*it);
		delete *it;
	}
	
}